package idv.jieh.commons.ftp;

import java.io.*;
import java.net.*;
import java.util.*;

import org.apache.commons.net.ProtocolCommandEvent;
import org.apache.commons.net.ProtocolCommandListener;
import org.apache.commons.net.ftp.*;

import idv.jieh.commons.util.DeBuger;

public class FTPAccess extends DeBuger{ // @todo 繼承錯了 ="= 應該改繼承 BasicClass

  private FTPClient client = null;
  private String errorMesg = "";
  private String RD = ""; // Root Directory
  private String CD = ""; // Current Directory

  private int TIMEOUT = 30000;
  private ProtocolCommandListener listener = null;

  public FTPAccess(String host, int port, String username, String password)
    throws IOException {
    this();
    if (!connect(host, port)) { return; }
    login(username, password);
  }

  public FTPAccess(String host, int port)
    throws IOException {
    this();
    connect(host, port);
  }

  public FTPAccess() {
    client = new FTPClient();
  }

  public boolean connect(String host, int port)
    throws SocketException, IOException {
    try {
      client.connect(host, port);
      client.setDataTimeout(TIMEOUT);
      return true;
    } catch (SocketException e) {
      super.exception(e);
      throw e;
    } catch (IOException e) {
      super.exception(e);
      throw e;
    }
  }

  public boolean login(String username, String password)
    throws IOException {
    try {
      if (client.login(username, password)) {
        CD = client.printWorkingDirectory();
        RD = CD;
        return true;
      } else {
        writeError();
        return false;
      }
    } catch (IOException e) {
      super.exception(e);
      throw e;
    }

  }

  public FTPFile[] getFileList(String path)
    throws IOException {
    FTPFile files[] = null;

    try {
      files = client.listFiles(path);
    } catch (IOException e) {
      super.equals(e);
      throw e;
    }
    return files;
  }

  public ArrayList download(
    String localPath,
    String remotePath,
    String likeName,
    boolean delete){
    ArrayList yes = new ArrayList();
    try {
      FTPFile[] list = getFileList(remotePath);
      String name;
      for(int i=0, l=list.length; i<l; i++){
        name = list[i].getName();
        if(	name.indexOf(likeName) != -1 &&
            download(list[i], localPath, remotePath, delete)){
          yes.add(name);
        }
      }
    } catch (IOException ex) {
      super.exception(ex);
    }
    return yes;
  }

  public ArrayList download(
    FTPFile files[],
    String localPath,
    String remotePath,
    boolean delete) {
    ArrayList yes = new ArrayList();
    for (int i=0, l=files.length; i<l; i++) {
      if(download(files[i], localPath, remotePath, delete))
        yes.add(files[i].getName());
    }
    return yes;
  }

  public boolean download(FTPFile file, String localPath, String remotePath, boolean delete) {
    boolean resultB = false;
    try {
      FileOutputStream fos = new FileOutputStream(new File(localPath + file.getName()));
      String name = file.getName();
      resultB = client.retrieveFile(remotePath + name, fos);
      if(delete) client.deleteFile(name);
      fos.flush();
      fos.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return resultB;
  }

  public boolean delete(String name){
    try {
      return client.deleteFile(name);
    } catch (Exception e) {
      e.printStackTrace();
      return false;
    }
  }

  public boolean upload(String localPath, String remotePath){
    boolean r = false;
    File file = new File(localPath);
    try {
      FileInputStream fis = new FileInputStream(file);
      r = client.appendFile(remotePath, fis);
      fis.close();
    } catch (FileNotFoundException ex) {
      super.exception(ex);
    } catch (IOException ex) {
      super.exception(ex);
    } catch (Exception ex) {
      super.exception(ex);
    }
    return r;
  }

  public boolean logout()
    throws IOException {
    try {
      if (!client.logout()) {
        writeError();
        return false;
      }
      return true;
    } catch (IOException e) {
      if (super.isDebug()) {
        e.printStackTrace();
      }
      throw e;
      //return false;
    }
  }

  public void close()
    throws IOException {
    try {
      client.disconnect();
    } catch (IOException e) {
      if (super.isDebug()) {
        e.printStackTrace();
      }
      throw e;
    }
  }

  public void setLogFile(File file)
    throws IOException {
    try {
      final FileOutputStream fos = new FileOutputStream(file);
      listener = new ProtocolCommandListener() {
        public void protocolCommandSent(ProtocolCommandEvent arg0) {
          try {
            if (isDebug()) {
              System.out.print(arg0.getMessage());
            }
            fos.write("COMMAND :".getBytes());
            fos.write(arg0.getMessage().getBytes());
          } catch (IOException e) {
            if (isDebug()) {
              e.printStackTrace();
            }
          }
        }

        public void protocolReplyReceived(ProtocolCommandEvent arg0) {
          try {
            if (isDebug()) {
              System.out.print(arg0.getMessage());
            }
            fos.write(arg0.getMessage().getBytes());
          } catch (IOException e) {
            if (isDebug()) {
              e.printStackTrace();
            }
          }
        }
      };
      client.addProtocolCommandListener(listener);
    } catch (FileNotFoundException e) {
      if (isDebug()) {
        e.printStackTrace();
      }
      throw e;
    }
  }

  private void writeError() {
    errorMesg = client.getReplyString();
  }

  public String getErrorString() {
    return errorMesg;
  }

  public String[] getErrorStrings() {
    return client.getReplyStrings();
  }
}
